#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
C盘空间分析和清理工具
扫描C盘所有文件和文件夹，按大小排序并列出可清理项
"""

import os
import sys
from pathlib import Path
from datetime import datetime
import operator


class DiskScanner:
    """磁盘扫描器"""
    
    def __init__(self, root_path="C:\\"):
        self.root_path = root_path
        self.file_list = []
        self.folder_list = []
        self.errors = []
        
        # 可清理的文件类型
        self.cleanable_extensions = {
            '.tmp', '.temp', '.log', '.bak', '.old', '.cache',
            '.dmp', '.chk', '.gid', '.~*'
        }
        
        # 可清理的文件夹（相对路径或名称）
        self.cleanable_folders = {
            'Temp', 'tmp', 'Trash', 'Recycle.Bin',
            '$Recycle.Bin', 'Thumbnails', 'Cache'
        }
        
        # Windows系统关键目录（不建议删除）
        self.system_folders = {
            'Windows', 'Program Files', 'Program Files (x86)',
            'ProgramData', 'System Volume Information',
            'Recovery', 'Boot', 'PerfLogs'
        }
    
    def get_folder_size(self, folder_path):
        """计算文件夹总大小"""
        total_size = 0
        try:
            for dirpath, dirnames, filenames in os.walk(folder_path):
                for filename in filenames:
                    file_path = os.path.join(dirpath, filename)
                    try:
                        total_size += os.path.getsize(file_path)
                    except (OSError, FileNotFoundError):
                        continue
        except (OSError, PermissionError) as e:
            self.errors.append(f"无法访问: {folder_path} - {str(e)}")
        return total_size
    
    def format_size(self, size):
        """格式化文件大小"""
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size < 1024.0:
                return f"{size:.2f} {unit}"
            size /= 1024.0
        return f"{size:.2f} PB"
    
    def is_cleanable_file(self, file_path):
        """判断文件是否可清理"""
        ext = Path(file_path).suffix.lower()
        return ext in self.cleanable_extensions
    
    def is_cleanable_folder(self, folder_path):
        """判断文件夹是否可清理"""
        folder_name = os.path.basename(folder_path)
        
        # 检查是否是系统关键文件夹
        if folder_name in self.system_folders:
            return False
        
        # 检查是否在可清理列表中
        if folder_name in self.cleanable_folders:
            return True
        
        # 检查是否是临时文件夹
        if 'temp' in folder_name.lower() or 'cache' in folder_name.lower():
            return True
        
        return False
    
    def scan_drive(self):
        """扫描驱动器"""
        print(f"开始扫描 {self.root_path} 驱动器...")
        print("这可能需要几分钟时间，请耐心等待...\n")
        
        scanned_files = 0
        scanned_folders = 0
        
        try:
            for root, dirs, files in os.walk(self.root_path):
                # 跳过系统保护的文件夹
                dirs[:] = [d for d in dirs if not d.startswith('$')]
                
                # 扫描文件夹
                for dir_name in dirs:
                    folder_path = os.path.join(root, dir_name)
                    try:
                        folder_size = self.get_folder_size(folder_path)
                        is_cleanable = self.is_cleanable_folder(folder_path)
                        
                        self.folder_list.append({
                            'path': folder_path,
                            'size': folder_size,
                            'cleanable': is_cleanable
                        })
                        
                        scanned_folders += 1
                        if scanned_folders % 100 == 0:
                            print(f"已扫描 {scanned_folders} 个文件夹...", end='\r')
                    
                    except (OSError, PermissionError) as e:
                        self.errors.append(f"无法访问文件夹: {folder_path}")
                        continue
                
                # 扫描文件
                for file_name in files:
                    file_path = os.path.join(root, file_name)
                    try:
                        file_size = os.path.getsize(file_path)
                        is_cleanable = self.is_cleanable_file(file_path)
                        
                        # 只记录大于1MB的文件或可清理的文件
                        if file_size > 1024 * 1024 or is_cleanable:
                            self.file_list.append({
                                'path': file_path,
                                'size': file_size,
                                'cleanable': is_cleanable
                            })
                        
                        scanned_files += 1
                        if scanned_files % 500 == 0:
                            print(f"已扫描 {scanned_files} 个文件...", end='\r')
                    
                    except (OSError, PermissionError) as e:
                        continue
        
        except KeyboardInterrupt:
            print("\n\n扫描已被用户中断！")
            return False
        
        print(f"\n扫描完成！共扫描 {scanned_files} 个文件，{scanned_folders} 个文件夹")
        return True
    
    def generate_report(self, output_file="disk_clean_report.txt"):
        """生成清理报告"""
        # 按大小排序
        sorted_files = sorted(self.file_list, key=operator.itemgetter('size'), reverse=True)
        sorted_folders = sorted(self.folder_list, key=operator.itemgetter('size'), reverse=True)
        
        # 计算可清理空间
        cleanable_file_size = sum(f['size'] for f in sorted_files if f['cleanable'])
        cleanable_folder_size = sum(f['size'] for f in sorted_folders if f['cleanable'])
        total_cleanable = cleanable_file_size + cleanable_folder_size
        
        # 生成报告
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write("=" * 80 + "\n")
            f.write(f"C盘空间分析报告 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write("=" * 80 + "\n\n")
            
            f.write(f"扫描路径: {self.root_path}\n")
            f.write(f"扫描文件数: {len(self.file_list)}\n")
            f.write(f"扫描文件夹数: {len(self.folder_list)}\n")
            f.write(f"预计可清理空间: {self.format_size(total_cleanable)}\n\n")
            
            # 最大的文件（前50个）
            f.write("=" * 80 + "\n")
            f.write("最大的文件 (前50个)\n")
            f.write("=" * 80 + "\n")
            for i, file_info in enumerate(sorted_files[:50], 1):
                cleanable_mark = "[可清理]" if file_info['cleanable'] else ""
                f.write(f"{i}. {cleanable_mark} {self.format_size(file_info['size']):>12} - {file_info['path']}\n")
            
            f.write("\n")
            
            # 最大的文件夹（前50个）
            f.write("=" * 80 + "\n")
            f.write("最大的文件夹 (前50个)\n")
            f.write("=" * 80 + "\n")
            for i, folder_info in enumerate(sorted_folders[:50], 1):
                cleanable_mark = "[可清理]" if folder_info['cleanable'] else ""
                f.write(f"{i}. {cleanable_mark} {self.format_size(folder_info['size']):>12} - {folder_info['path']}\n")
            
            f.write("\n")
            
            # 可清理的文件
            cleanable_files = [f for f in sorted_files if f['cleanable']]
            if cleanable_files:
                f.write("=" * 80 + "\n")
                f.write(f"可清理的文件 (共 {len(cleanable_files)} 个)\n")
                f.write("=" * 80 + "\n")
                for i, file_info in enumerate(cleanable_files[:100], 1):
                    f.write(f"{i}. {self.format_size(file_info['size']):>12} - {file_info['path']}\n")
                
                f.write(f"\n可清理文件总大小: {self.format_size(cleanable_file_size)}\n\n")
            
            # 可清理的文件夹
            cleanable_folders = [f for f in sorted_folders if f['cleanable']]
            if cleanable_folders:
                f.write("=" * 80 + "\n")
                f.write(f"可清理的文件夹 (共 {len(cleanable_folders)} 个)\n")
                f.write("=" * 80 + "\n")
                for i, folder_info in enumerate(cleanable_folders[:50], 1):
                    f.write(f"{i}. {self.format_size(folder_info['size']):>12} - {folder_info['path']}\n")
                
                f.write(f"\n可清理文件夹总大小: {self.format_size(cleanable_folder_size)}\n\n")
            
            # 错误日志
            if self.errors:
                f.write("=" * 80 + "\n")
                f.write(f"扫描错误 (共 {len(self.errors)} 个)\n")
                f.write("=" * 80 + "\n")
                for error in self.errors[:100]:
                    f.write(f"- {error}\n")
        
        print(f"\n报告已生成: {output_file}")
        print(f"预计可清理空间: {self.format_size(total_cleanable)}")
        
        # 控制台输出摘要
        print("\n" + "=" * 80)
        print("可清理项摘要 (前10项)")
        print("=" * 80)
        
        print("\n最大的可清理文件:")
        for i, file_info in enumerate(cleanable_files[:10], 1):
            print(f"{i}. {self.format_size(file_info['size']):>12} - {file_info['path']}")
        
        print("\n最大的可清理文件夹:")
        for i, folder_info in enumerate(cleanable_folders[:10], 1):
            print(f"{i}. {self.format_size(folder_info['size']):>12} - {folder_info['path']}")


def main():
    """主函数"""
    print("=" * 80)
    print("C盘空间分析和清理工具")
    print("=" * 80)
    print("\n警告: 此工具将扫描整个C盘，可能需要较长时间！")
    print("注意: 请勿随意删除系统文件，建议手动确认后再删除！\n")
    
    # 检查是否有管理员权限
    try:
        is_admin = os.getuid() == 0
    except AttributeError:
        import ctypes
        is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
    
    if not is_admin:
        print("建议: 以管理员权限运行此程序以获得完整的扫描结果\n")
    
    # 创建扫描器
    scanner = DiskScanner("C:\\")
    
    # 执行扫描
    if scanner.scan_drive():
        # 生成报告
        scanner.generate_report("disk_clean_report.txt")
        print("\n扫描完成！请查看 disk_clean_report.txt 了解详细信息")
    else:
        print("\n扫描未完成")


if __name__ == "__main__":
    main()
